#include "auto_door_protocol.h"

namespace application {
namespace auto_door {

AutoDoorProtocol::AutoDoorProtocol(std::shared_ptr<kernel::ILogger> logger, QObject* parent)
    : QObject(parent)
    , m_logger(logger)
{
}

// ========== CRC16-CCITT 计算 ==========

uint16_t AutoDoorProtocol::calculateCrc16(const QByteArray& data) const
{
    uint16_t crc = 0xFFFF;  // 初值
    const uint16_t poly = 0x1021;  // CRC16-CCITT 多项式

    for (int i = 0; i < data.size(); ++i) {
        crc ^= (static_cast<uint16_t>(static_cast<uint8_t>(data[i])) << 8);

        for (int j = 0; j < 8; ++j) {
            if (crc & 0x8000) {
                crc = (crc << 1) ^ poly;
            } else {
                crc <<= 1;
            }
        }
    }

    return crc;
}

// ========== 帧构建（编码） ==========

QByteArray AutoDoorProtocol::buildFrame(LedMsgType msgType, const QByteArray& payload, uint16_t sequence)
{
    QByteArray frame;

    // 1. 帧头
    frame.append(static_cast<char>(0xAA));
    frame.append(static_cast<char>(0x55));

    // 2. 版本
    frame.append(static_cast<char>(PROTOCOL_VERSION));

    // 3. 消息类型
    frame.append(static_cast<char>(msgType));

    // 4. 载荷长度（大端）
    uint16_t payloadLen = static_cast<uint16_t>(payload.size());
    frame.append(static_cast<char>((payloadLen >> 8) & 0xFF));
    frame.append(static_cast<char>(payloadLen & 0xFF));

    // 5. 流水号（大端）
    frame.append(static_cast<char>((sequence >> 8) & 0xFF));
    frame.append(static_cast<char>(sequence & 0xFF));

    // 6. 载荷
    frame.append(payload);

    // 7. CRC16 计算（从Version到Payload末尾）
    QByteArray crcData = frame.mid(2);  // 跳过帧头 0xAA 0x55
    uint16_t crc = calculateCrc16(crcData);

    // 8. CRC16（大端）
    frame.append(static_cast<char>((crc >> 8) & 0xFF));
    frame.append(static_cast<char>(crc & 0xFF));

    return frame;
}

QByteArray AutoDoorProtocol::buildHelloAck(quint32 deviceId, uint8_t result, uint16_t sequence)
{
    QByteArray payload;

    // DeviceId（4字节大端）
    payload.append(static_cast<char>((deviceId >> 24) & 0xFF));
    payload.append(static_cast<char>((deviceId >> 16) & 0xFF));
    payload.append(static_cast<char>((deviceId >> 8) & 0xFF));
    payload.append(static_cast<char>(deviceId & 0xFF));

    // Result（1字节）
    payload.append(static_cast<char>(result));

    return buildFrame(LedMsgType::HELLO_ACK, payload, sequence);
}

QByteArray AutoDoorProtocol::buildHeartbeatAck(quint32 deviceId, uint8_t result, uint16_t sequence)
{
    QByteArray payload;

    // DeviceId（4字节大端）
    payload.append(static_cast<char>((deviceId >> 24) & 0xFF));
    payload.append(static_cast<char>((deviceId >> 16) & 0xFF));
    payload.append(static_cast<char>((deviceId >> 8) & 0xFF));
    payload.append(static_cast<char>(deviceId & 0xFF));

    // Result（1字节）
    payload.append(static_cast<char>(result));

    return buildFrame(LedMsgType::HEARTBEAT_ACK, payload, sequence);
}

QByteArray AutoDoorProtocol::buildLedControl(uint32_t programId, uint8_t levelMask, uint16_t sequence)
{
    QByteArray payload;

    // ProgramID（4字节大端）
    payload.append(static_cast<char>((programId >> 24) & 0xFF));
    payload.append(static_cast<char>((programId >> 16) & 0xFF));
    payload.append(static_cast<char>((programId >> 8) & 0xFF));
    payload.append(static_cast<char>(programId & 0xFF));

    // LevelMask（1字节，只使用低3位）
    payload.append(static_cast<char>(levelMask & 0x07));

    return buildFrame(LedMsgType::LED_CONTROL, payload, sequence);
}

// ========== 帧解析（解码） ==========

void AutoDoorProtocol::appendData(const QByteArray& data)
{
    m_receiveBuffer.append(data);

    // 限制缓冲区大小防止内存膨胀
    if (m_receiveBuffer.size() > 1024) {
        if (m_logger) {
            m_logger->warning("接收缓冲区超限，清空前512字节");
        }
        m_receiveBuffer.remove(0, 512);
    }
}

int AutoDoorProtocol::findPreamble() const
{
    for (int i = 0; i < m_receiveBuffer.size() - 1; ++i) {
        if (static_cast<uint8_t>(m_receiveBuffer[i]) == 0xAA &&
            static_cast<uint8_t>(m_receiveBuffer[i + 1]) == 0x55) {
            return i;
        }
    }
    return -1;
}

bool AutoDoorProtocol::parseFrame()
{
    // 1. 查找帧头
    int preamblePos = findPreamble();
    if (preamblePos == -1) {
        // 没有帧头，清空缓冲区
        if (m_receiveBuffer.size() > 1) {
            m_receiveBuffer.clear();
        }
        return false;
    }

    // 2. 对齐到帧头
    if (preamblePos > 0) {
        m_receiveBuffer.remove(0, preamblePos);
    }

    // 3. 检查是否有足够数据解析帧头（至少8字节：帧头2 + Version1 + MsgType1 + Length2 + Sequence2）
    if (m_receiveBuffer.size() < 8) {
        return false;
    }

    // 4. 解析帧头信息
    uint8_t version = static_cast<uint8_t>(m_receiveBuffer[2]);
    LedMsgType msgType = static_cast<LedMsgType>(static_cast<uint8_t>(m_receiveBuffer[3]));
    uint16_t payloadLength = (static_cast<uint16_t>(static_cast<uint8_t>(m_receiveBuffer[4])) << 8) |
                             static_cast<uint16_t>(static_cast<uint8_t>(m_receiveBuffer[5]));
    uint16_t sequence = (static_cast<uint16_t>(static_cast<uint8_t>(m_receiveBuffer[6])) << 8) |
                        static_cast<uint16_t>(static_cast<uint8_t>(m_receiveBuffer[7]));

    // 5. 校验载荷长度
    if (payloadLength > MAX_PAYLOAD_LENGTH) {
        if (m_logger) {
            m_logger->warning(QString("载荷长度超限: %1 > %2").arg(payloadLength).arg(MAX_PAYLOAD_LENGTH));
        }
        emit protocolError(QString("Payload length exceeds limit: %1").arg(payloadLength));
        // 丢弃当前帧头，继续查找下一帧
        m_receiveBuffer.remove(0, 2);
        return false;
    }

    // 6. 检查是否接收完整帧（帧头8 + 载荷N + CRC2）
    int frameSize = 8 + payloadLength + 2;
    if (m_receiveBuffer.size() < frameSize) {
        return false;  // 数据不完整，等待更多数据
    }

    // 7. 提取载荷和CRC
    QByteArray payload = m_receiveBuffer.mid(8, payloadLength);
    uint16_t receivedCrc = (static_cast<uint16_t>(static_cast<uint8_t>(m_receiveBuffer[frameSize - 2])) << 8) |
                           static_cast<uint16_t>(static_cast<uint8_t>(m_receiveBuffer[frameSize - 1]));

    // 8. 计算CRC（从Version到Payload末尾）
    QByteArray crcData = m_receiveBuffer.mid(2, frameSize - 4);  // 跳过帧头和CRC本身
    uint16_t calculatedCrc = calculateCrc16(crcData);

    // 9. 校验CRC
    if (receivedCrc != calculatedCrc) {
        if (m_logger) {
            m_logger->warning(QString("CRC校验失败: 接收=0x%1, 计算=0x%2")
                .arg(receivedCrc, 4, 16, QChar('0'))
                .arg(calculatedCrc, 4, 16, QChar('0')));
        }
        emit protocolError(QString("CRC mismatch: received=0x%1, calculated=0x%2")
            .arg(receivedCrc, 4, 16, QChar('0'))
            .arg(calculatedCrc, 4, 16, QChar('0')));
        // 丢弃当前帧头，继续查找下一帧
        m_receiveBuffer.remove(0, 2);
        return false;
    }

    // 10. 校验版本
    if (version != PROTOCOL_VERSION) {
        if (m_logger) {
            m_logger->warning(QString("协议版本不匹配: 接收=0x%1, 期望=0x%2")
                .arg(version, 2, 16, QChar('0'))
                .arg(PROTOCOL_VERSION, 2, 16, QChar('0')));
        }
        emit protocolError(QString("Protocol version mismatch: %1").arg(version));
        m_receiveBuffer.remove(0, frameSize);
        return false;
    }

    // 11. 根据消息类型分发处理
    switch (msgType) {
        case LedMsgType::HELLO:
            parseHello(payload, sequence);
            break;
        case LedMsgType::HEARTBEAT:
            parseHeartbeat(payload, sequence);
            break;
        case LedMsgType::LED_ACK:
            parseLedAck(payload, sequence);
            break;
        case LedMsgType::LED_ERROR:
            parseLedError(payload, sequence);
            break;
        default:
            if (m_logger) {
                m_logger->warning(QString("未知消息类型: 0x%1").arg(static_cast<uint8_t>(msgType), 2, 16, QChar('0')));
            }
            emit protocolError(QString("Unknown message type: 0x%1").arg(static_cast<uint8_t>(msgType), 2, 16, QChar('0')));
            break;
    }

    // 12. 移除已解析的帧
    m_receiveBuffer.remove(0, frameSize);

    return true;
}

// ========== 载荷解析 ==========

void AutoDoorProtocol::parseHello(const QByteArray& payload, uint16_t sequence)
{
    if (payload.size() < 7) {  // DeviceId(4) + FwVersion(2) + Flags(1)
        emit protocolError("HELLO payload too short");
        return;
    }

    // 解析 DeviceId（4字节大端）
    quint32 deviceId = (static_cast<quint32>(static_cast<uint8_t>(payload[0])) << 24) |
                       (static_cast<quint32>(static_cast<uint8_t>(payload[1])) << 16) |
                       (static_cast<quint32>(static_cast<uint8_t>(payload[2])) << 8) |
                       static_cast<quint32>(static_cast<uint8_t>(payload[3]));

    // 解析 FwVersion（2字节大端）
    uint16_t fwVersion = (static_cast<uint16_t>(static_cast<uint8_t>(payload[4])) << 8) |
                         static_cast<uint16_t>(static_cast<uint8_t>(payload[5]));

    // 解析 Flags（1字节）
    uint8_t flags = static_cast<uint8_t>(payload[6]);

    if (m_logger) {
        m_logger->info(QString("收到HELLO: DeviceId=0x%1, FwVersion=0x%2, Flags=0x%3")
            .arg(deviceId, 8, 16, QChar('0'))
            .arg(fwVersion, 4, 16, QChar('0'))
            .arg(flags, 2, 16, QChar('0')));
    }

    emit helloReceived(deviceId, fwVersion, flags, sequence);
}

void AutoDoorProtocol::parseHeartbeat(const QByteArray& payload, uint16_t sequence)
{
    if (payload.size() < 8) {  // DeviceId(4) + Uptime(4)
        emit protocolError("HEARTBEAT payload too short");
        return;
    }

    // 解析 DeviceId（4字节大端）
    quint32 deviceId = (static_cast<quint32>(static_cast<uint8_t>(payload[0])) << 24) |
                       (static_cast<quint32>(static_cast<uint8_t>(payload[1])) << 16) |
                       (static_cast<quint32>(static_cast<uint8_t>(payload[2])) << 8) |
                       static_cast<quint32>(static_cast<uint8_t>(payload[3]));

    // 解析 Uptime（4字节大端）
    uint32_t uptime = (static_cast<uint32_t>(static_cast<uint8_t>(payload[4])) << 24) |
                      (static_cast<uint32_t>(static_cast<uint8_t>(payload[5])) << 16) |
                      (static_cast<uint32_t>(static_cast<uint8_t>(payload[6])) << 8) |
                      static_cast<uint32_t>(static_cast<uint8_t>(payload[7]));

    emit heartbeatReceived(deviceId, uptime, sequence);
}

void AutoDoorProtocol::parseLedAck(const QByteArray& payload, uint16_t sequence)
{
    if (payload.size() < 5) {  // ProgramId(4) + LevelMask(1)
        emit protocolError("LED_ACK payload too short");
        return;
    }

    // 解析 ProgramId（4字节大端）
    uint32_t programId = (static_cast<uint32_t>(static_cast<uint8_t>(payload[0])) << 24) |
                         (static_cast<uint32_t>(static_cast<uint8_t>(payload[1])) << 16) |
                         (static_cast<uint32_t>(static_cast<uint8_t>(payload[2])) << 8) |
                         static_cast<uint32_t>(static_cast<uint8_t>(payload[3]));

    // 解析 LevelMask（1字节）
    uint8_t levelMask = static_cast<uint8_t>(payload[4]);

    if (m_logger) {
        m_logger->debug(QString("收到LED_ACK: ProgramId=0x%1, LevelMask=0x%2")
            .arg(programId, 8, 16, QChar('0'))
            .arg(levelMask, 2, 16, QChar('0')));
    }

    emit ledAckReceived(programId, levelMask, sequence);
}

void AutoDoorProtocol::parseLedError(const QByteArray& payload, uint16_t sequence)
{
    if (payload.size() < 5) {  // ProgramId(4) + ErrorCode(1)
        emit protocolError("LED_ERROR payload too short");
        return;
    }

    // 解析 ProgramId（4字节大端）
    uint32_t programId = (static_cast<uint32_t>(static_cast<uint8_t>(payload[0])) << 24) |
                         (static_cast<uint32_t>(static_cast<uint8_t>(payload[1])) << 16) |
                         (static_cast<uint32_t>(static_cast<uint8_t>(payload[2])) << 8) |
                         static_cast<uint32_t>(static_cast<uint8_t>(payload[3]));

    // 解析 ErrorCode（1字节）
    LedErrorCode errorCode = static_cast<LedErrorCode>(static_cast<uint8_t>(payload[4]));

    if (m_logger) {
        m_logger->warning(QString("收到LED_ERROR: ProgramId=0x%1, ErrorCode=0x%2")
            .arg(programId, 8, 16, QChar('0'))
            .arg(static_cast<uint8_t>(errorCode), 2, 16, QChar('0')));
    }

    emit ledErrorReceived(programId, errorCode, sequence);
}

// ========== 流水号管理 ==========

uint16_t AutoDoorProtocol::getNextSequence()
{
    return m_sequence++;
}

} // namespace auto_door
} // namespace application
